package pdf.pdfbox;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.encryption.*;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.pdfbox.util.Matrix;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Iterator;

public class PdfUtil {

    /**
     * 创建水印
     *
     * @param path          源文件路径
     * @param savePath      新文件路径
     * @param watermarkText 水印内容
     */
    public static void createWatermark(String path, String savePath, String watermarkText) {
        PDDocument pdfDoc = null;
        try {
            pdfDoc = PDDocument.load(new File(path));
            pdfDoc.setAllSecurityToBeRemoved(true);
            for (PDPage page : pdfDoc.getPages()) {
                PDPageContentStream cs = new PDPageContentStream(pdfDoc, page, PDPageContentStream.AppendMode.APPEND, true, true);
                PDFont font = PDType0Font.load(pdfDoc, new FileInputStream(new File("SIMYOU.TTF")), false);
                PDExtendedGraphicsState r0 = new PDExtendedGraphicsState();
                r0.setNonStrokingAlphaConstant(0.5f); // 透明度
                r0.setAlphaSourceFlag(true);
                cs.setGraphicsStateParameters(r0);
                cs.setNonStrokingColor(new Color(222, 222, 222));
                cs.beginText();
                cs.setFont(font, 38F);
                //设置位置
                cs.setTextMatrix(Matrix.getRotateInstance(20, 350f, 490f));

                cs.showText(watermarkText);
                cs.endText();
                cs.close();
            }
            pdfDoc.save(savePath);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (pdfDoc != null) {
                try {
                    pdfDoc.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 生成 PDF 的缩略图
     *
     * @param filePath 需要生成缩略图的 PDF 的完整路径
     * @param outPath  生成缩略图的放置路径
     */
    public static void thumbnails(String filePath, String outPath) throws IOException {
        // 利用PdfBox生成图像
        PDDocument pdfDoc = null;
        FileOutputStream fos = null;
        ImageOutputStream ios = null;
        try {
            pdfDoc = PDDocument.load(new File(filePath));
            PDFRenderer renderer = new PDFRenderer(pdfDoc);
            // 构造图片
            BufferedImage bufferedImage = renderer.renderImageWithDPI(0, 30, ImageType.RGB);
            // 设置图片格式
            Iterator<ImageWriter> it = ImageIO.getImageWritersBySuffix("png");
            // 将文件写出
            ImageWriter writer = it.next();
            fos = new FileOutputStream(outPath);
            ios = ImageIO.createImageOutputStream(fos);
            writer.setOutput(ios);
            writer.write(new IIOImage(bufferedImage, null, null));
        } catch (IOException e) {
            throw e;
        } finally {
            if (ios != null) {
                ios.close();
            }
            if (fos != null) {
                fos.close();
            }
            if(pdfDoc != null){
                pdfDoc.close();
            }
        }

    }

    /**
     * PDF转图片 根据页码一页一页转
     */
    public static void PDFToImg(OutputStream sos, String fileUrl, int page, String imgType) throws IOException {
        PDDocument pdfDoc = null;
        //dpi越大转换后越清晰，相对转换速度越慢
        int dpi = 1000;
        try {
            pdfDoc = PDDocument.load(new File(fileUrl));
            PDFRenderer renderer = new PDFRenderer(pdfDoc);
            int pages = pdfDoc.getNumberOfPages();
            if (page <= pages && page >= 0) {
                BufferedImage image = renderer.renderImageWithDPI(page, dpi);
                ImageIO.write(image, imgType, sos);
            }
        } catch (IOException e) {
            throw e;
        } finally {
            if (pdfDoc != null) {
                try {
                    pdfDoc.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**
     * 加密pdf
     *
     * @param path     待加密pdf地址
     * @param savePath 保存地址
     */
    public static void encryptPDF(String path, String savePath) throws IOException {
        String ownerPassWord = "123"; //所有者密码(设置权限的密码) -- 使用此密码可以打开文件并且拥有所有权限
        String userPassWord = "456"; //用户密码(打开文件密码) -- 使用此密码只能打开文件
        PDDocument pdfDoc = null;
        try {
            pdfDoc = PDDocument.load(new File(path));
            AccessPermission permissions = new AccessPermission();
            // 是否可以插入/删除/旋转页面
            permissions.setCanAssembleDocument(false);
            // 是否可以复制和提取内容
            permissions.setCanExtractContent(false);

            permissions.setCanExtractForAccessibility(false);
            // 设置用户是否可以填写交互式表单字段（包括签名字段）
            permissions.setCanFillInForm(false);
            // 设置用户是否可以修改文档
            permissions.setCanModify(false);
            // 设置用户是否可以添加或修改文本注释并填写交互式表单字段，如果canModify()返回true，则创建或修改交互式表单字段（包括签名字段）。
            permissions.setCanModifyAnnotations(false);
            // 设置用户是否可以打印。
            permissions.setCanPrint(false);
            // 设置用户是否可以降级格式打印文档
            permissions.setCanPrintDegraded(false);

            StandardProtectionPolicy p = new StandardProtectionPolicy(ownerPassWord, null, permissions);
            SecurityHandler sh = new StandardSecurityHandler(p);
            sh.prepareDocumentForEncryption(pdfDoc);
            PDEncryption encryptionOptions = new PDEncryption();
            encryptionOptions.setSecurityHandler(sh);

            pdfDoc.setEncryptionDictionary(encryptionOptions);
            pdfDoc.save(savePath);
        } catch (IOException e) {
            throw e;
        } finally {
            if (pdfDoc != null) {
                try {
                    pdfDoc.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**
     * 解密pdf(只能解密没有打开文件密码的pdf)
     *
     * @param path     待解密pdf地址
     * @param savePath 保存地址
     */
    public static void decryptPDF(String path, String savePath) throws IOException {
        PDDocument pdfDoc = null;
        try {
            pdfDoc = PDDocument.load(new File(path));
            pdfDoc.setAllSecurityToBeRemoved(true);
            pdfDoc.save(savePath);
        } catch (IOException e) {
            throw e;
        } finally {
            if (pdfDoc != null) {
                try {
                    pdfDoc.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
